#    Stingingnettlepy - A website generator for creating simple static websites.
#    Copyright (C) 2013  Jannik Haberbosch
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


# Standard Python modules
import os
import os.path
import json
import re
import collections
import shutil

# Project modules.
from stingingnettlepy.constants import constants
from stingingnettlepy import dict_functions
from stingingnettlepy.classes.Template import Template
from stingingnettlepy import navigation_functions


def main():
	"""Generates the website.

	"""
	# Load the website structure.  It must be valid.
	try:
		site_structure = json.load(
			open( constants.RELPATH_SITE_STRUCTURE ),
			object_pairs_hook = collections.OrderedDict
		)
	except ValueError as e:
		print( constants.ERR_MSG_LOAD_SITE_STRUCTURE %
			( constants.RELPATH_SITE_STRUCTURE, e )
		)
		return 0

	
	# Make sure that all specified templates exist.
	found_templates_in_site_structure = []
	keys = dict_functions.walk( site_structure )
	for key in keys:
		result = re.search( "template:[A-Za-z0-9_]*", key )
		if result is not None:
			# Add the name of the found template (remove the "template:" part)
			# But append a ".html" extension.
			found_templates_in_site_structure.append(
				result.group( 0 ).split( ":" )[1] + constants.EXT_HTML
			)

	templates_exist = True
	for template in found_templates_in_site_structure:
		if not os.path.exists(
			os.path.join( constants.RELPATH_TEMPLATES, template )
		):
			print( constants.MSG_ERR_TEMPLATE_DOES_NOT_EXIST % template )
			if templates_exist:
				templates_exist = False

	if templates_exist == False:
		return 0


	# Load the templates.
	templates = load_templates()

	# Generate the website.
	generate_website( site_structure, templates )

	# Copy JS, CSS, media and downloads files over to the "/out" directory.
	dirs = ( constants.RELPATH_OUT_CSS, constants.RELPATH_OUT_JS, constants.RELPATH_OUT_MEDIA, constants.RELPATH_OUT_DOWNLOADS )
	for d in dirs:
		if os.path.exists( d ):
			shutil.rmtree( d )
			
		shutil.copytree(
			d.replace( "out", "in", 1 ),
			d
		)
		shutil.copystat(
			d.replace( "out", "in", 1 ),
			d
		)


def generate_website( site_structure, templates, cur_path_out = constants.RELPATH_OUT, cur_path_in = constants.RELPATH_PAGES ):

	for k, v in site_structure.items():
		# Use the default template?
		result = re.search( "template:[A-Za-z0-9_]*", k )
		if result is None:
			# Use the default template.		
			template_name = constants.DEFAULT_TEMPLATE + constants.EXT_HTML
			template = get_template( templates, template_name )
		else:
			# Use another template.		
			template_name = result.group( 0 ).split( ":" )[1] + constants.EXT_HTML
			template = get_template( templates, template_name )
				
		if "template:" in k:
			d = k.split( "template:" )[0].strip().replace( " ", "_" )
		else:
			d = k.strip().replace( " ", "_" )
		
		try:
			os.makedirs(
				os.path.join( cur_path_out, d )
			)
		except:
			pass
		

		# Load the contents of all containers for a certain page.
		containers_content = load_containers(
			os.path.join( cur_path_in, d )
		)

		# Create the content for the "index.html" file:
		html_file = dict_replace( template.content, containers_content )
		# Create the index.html file.  This will contain the content of a
		# specific page.
		with open(
			os.path.join( cur_path_out, d, "index.html" ), "w"
		) as f:
			f.write( html_file )
		if len( v ) > 0:
			generate_website(
				v,
				templates,
				os.path.join(
					cur_path_out, d
				),
				os.path.join(
					cur_path_in, d
				)
			)


def load_templates():
	"""Creates template objects that represent templates (by using the class
	Template, and returns a list containing those instances.

	"""
	templates = []
	for template_filename in os.listdir( constants.RELPATH_TEMPLATES ):
		templates.append(
			Template(
				os.path.join( constants.RELPATH_TEMPLATES, template_filename )
			)
		)
		
	return templates


def get_template( templates, template_name ):
	"""Returns a Template instances of the 'templates' tuple of which the
	'Template.name' property matches 'template_name'.

	"""
	for template in templates:
		if template.name == template_name:
			return template


def load_containers( dir_path ):
	"""Loads the contents of the containers and returns a dictionary, where the
	keys are the names of the containers and the values the content of a
	container.

	"""
	containers = {}
	for x in os.listdir( dir_path ):
		if os.path.isdir(
			os.path.join( dir_path, x )
		):
			continue
		with open( os.path.join(
			dir_path, x )
		) as f:
			container_content = f.read()

		if x == "mainnavigation" or x == "subnavigation":
			y = "%s%s%s" % ( "%", x, "%" )
		else:
			y = "#%s#" % x
		containers.update(
			{
				y: container_content
			}
		)

	return containers


def dict_replace( raw, replacements ):
	for key, value in replacements.items():
		raw = raw.replace( key, value )
	return raw
